//
//  HJJT.m
//  YGMobile
//
//  Created by zhanglu on 2017/2/13.
//  Copyright © 2017年 Elephants Financial Service. All rights reserved.
//

#include "HJJT.h"
#include "HJJTSQLite.h"

using namespace ytx;
using namespace std;


HJJT::HJJT(IndexConfig indexConfig):IndexData(indexConfig, 0), requesLock(false)
{
    indexName = "HJJT";
    type = QuotationType::HJJT;
}

void HJJT::callback(string tag, string data)
{
    YTXJson::Reader reader;
    YTXJson::Value value;
    
    try {
        reader.parse(data, value);
        requesLock = false;
        
        if (this->kLineData == nil) {
            return;
        }
        
        if(tag == "HJJTData"+this->kLineData->id)
        {
            responseHJJTData(value["SignalData"], value["info"]);
        }
        else if(tag == "HJJTDataFront"+this->kLineData->id)
        {
            responseHJJTDataFront(value["SignalData"], value["info"]);
        }
        else if(tag == "HJJTDataBack"+this->kLineData->id)
        {
            responseHJJTDataBack(value["SignalData"], value["info"]);
        }
    } catch (void * __attribute__((annotate("oclint:suppress[unused local variable]"))) ex) {
        NSLog(@"%@", ex);
    }
}

void HJJT::onFail(string tag)
{
    requesLock = false;
}

void HJJT::realCalculate(KLineData * data)
{
    indexData.clear();
    lineData.clear();
    
    if ( HJJTData.size() == 0 || !data->hasDataWithoutClose()) {
        return;
    }
    
    //先设置为灰色
    vector<double> position;
    
    //lineData为了参与最高最低的计算
    vector<double> beginPrice;
    vector<double> endPrice;
    vector<double> upLine;
    vector<double> bottom;
    vector<double> sUpLine;
    vector<double> upMid;
    vector<double> downMid;
    vector<double> sBottom;
    vector<double> trend;
    vector<double> temper;
    
    int beginIndex = 0;
    int endIndex;
    NSLog(@"HJJT,begin:%s||end:%s\nkLine,begin:%s||end:%s",HJJTData.front().signalTime.toStringYYYYMMddHHmmss().c_str(), HJJTData.back().signalTime.toStringYYYYMMddHHmmss().c_str(), kLineData->kLineData.front().dateTime.toStringYYYYMMddHHmmss().c_str(), kLineData->kLineData.back().dateTime.toStringYYYYMMddHHmmss().c_str());

    vector<HJJTItem>::iterator HJJTIt = HJJTData.begin();
    for (vector<KLineItem>::iterator kLineIt = data->kLineData.begin();;) {
        
        HJJTItem it = (*HJJTIt);

        if (HJJTIt == HJJTData.end()) {
            it = HJJTData.back();
            endIndex = (int)(data->kLineData.end() - data->kLineData.begin());
            for (int i = beginIndex;i < endIndex;i++) {
                position.push_back(0);
                beginPrice.push_back(it.beginPrice);
                endPrice.push_back(it.endPrice);
                upLine.push_back(it.upLine);
                bottom.push_back(it.bottom);
                sUpLine.push_back(it.sUpLine);
                upMid.push_back(it.upMid);
                downMid.push_back(it.downMid);
                sBottom.push_back(it.sBottom);
                trend.push_back(it.trend);
                temper.push_back(it.temper);
            }
            break;
        }
        if (kLineIt == data->kLineData.end()) {
            break;
        }
        KLineItem k = (*kLineIt);

        endIndex = getHJJTIndexInKLinedata(it.signalTime, data);
        
        if (endIndex == -1) {
            ++HJJTIt;
            if (it.signalTime >= k.dateTime ){
                ++kLineIt;
            }
            continue;
        }
        for (int i = beginIndex;i < endIndex;i++) {
            position.push_back(0);
            beginPrice.push_back(it.beginPrice);
            endPrice.push_back(it.endPrice);
            upLine.push_back(it.upLine);
            bottom.push_back(it.bottom);
            sUpLine.push_back(it.sUpLine);
            upMid.push_back(it.upMid);
            downMid.push_back(it.downMid);
            sBottom.push_back(it.sBottom);
            trend.push_back(it.trend);
            temper.push_back(it.temper);
        }

        position.push_back(it.position);
        beginPrice.push_back(it.beginPrice);
        endPrice.push_back(it.endPrice);
        upLine.push_back(it.upLine);
        bottom.push_back(it.bottom);
        sUpLine.push_back(it.sUpLine);
        upMid.push_back(it.upMid);
        downMid.push_back(it.downMid);
        sBottom.push_back(it.sBottom);
        trend.push_back(it.trend);
        temper.push_back(it.temper);
        
        kLineIt+=(endIndex-beginIndex);
        beginIndex = endIndex+1;
        ++HJJTIt;
    }
    indexData.push_back(position);
    
    lineData.push_back(beginPrice);
    lineData.push_back(endPrice);
    indexData.push_back(upLine);
    indexData.push_back(bottom);
    indexData.push_back(sUpLine);
    indexData.push_back(upMid);
    indexData.push_back(downMid);
    indexData.push_back(sBottom);
    
    indexData.push_back(trend);
    indexData.push_back(temper);
}

int HJJT::getHJJTIndexInKLinedata(YTXTime time, KLineData * data)
{
    if (time >= data->kLineData.back().dateTime) {
        return data->getDataLength() - 1;
    }
    
    for (vector<KLineItem>::iterator kLineIt = data->kLineData.begin(); kLineIt != data->kLineData.end() - 1; ++kLineIt) {
        KLineItem k = (*kLineIt);
        
        if (k.dateTime == time)
        {
            return (int)(kLineIt - data->kLineData.begin());
        }
        
    }
    return -1;
}


void HJJT::calculate(Quotation * data)
{
    this->kLineData = (KLineData *)data;
    getHJJTData();
}

void HJJT::updateLastest(Quotation * data)
{
    calculate(data);
}

bool HJJT::hasHJJTData()
{
    return HJJTData.size() > 0;
}

//调用时需要判断有没有QK
//getK已经有数据 或者 response 监听分时变化时也要判断
void HJJT::getHJJTData()
{
    if (!this->kLineData->getIndexConfig(IndexType::HJJT).isParticularAndHas()) {
        return;
    }
//    HJJTSQLite HJJTSQLite;
//    
//    HJJTSQLite.createKLineDataTableIfNotExit(HJJTSQLite::getTableName(kLineData));
    
    if (!kLineData->hasDataWithoutClose()) {
        return;
    }
    
//    if (!hasHJJTData()) {
        //+1是算出来那条的长度
//        HJJTData = getHJJTDataFromDB(YTXTime(2200,1,1,0,0,0), kLineData->getDataLengthWithoutClose()+1);
//    }
    //    NSLog(@"klength:%d thislength:%d", kLineData->getDataLength(), getDataLength());
    if (hasHJJTData()) {
//        bool cacheInvalidation = kLineData->isCacheInvalidation(HJJTData.back().signalTime, YTXTime().GMT8());
    
//        if (!cacheInvalidation) {
//            cleanData();
//            HJJTSQLite.clearTable(HJJTSQLite::getTableName(this));
//            requestHJJTData();
//            return;
//        }

        
        //        NSString * kf = [NSString stringWithUTF8String: this->kLineData->kLineData.front().dateTime.toStringMMddHHmmss().c_str()];
        //        NSString * gsf = [NSString stringWithUTF8String: HJJTData.front().tradedate.toStringMMddHHmmss().c_str()];
        //
        //        NSString * kb = [NSString stringWithUTF8String: this->kLineData->kLineData.back().dateTime.toStringMMddHHmmss().c_str()];
        //        NSString * gsb = [NSString stringWithUTF8String: HJJTData.back().tradedate.toStringMMddHHmmss().c_str()];
        //
        //        NSLog(@"kf:%@ gsf:%@",kf, gsf);
        //        NSLog(@"kb:%@ gsb:%@",kb, gsb);
        
        NSLog(@"HJJT,begin:%ld||end:%ld\nkLine,begin:%ld||end:%ld",HJJTData.front().signalTime.toSeconds(), HJJTData.back().signalTime.toSeconds(), kLineData->kLineData.front().dateTime.toSeconds(), kLineData->kLineData.back().dateTime.toSeconds());

        if (HJJTData.back().signalTime < kLineData->kLineData[kLineData->kLineData.end() - kLineData->kLineData.begin() - 2].dateTime) {
            //取未来
            getHJJTDataBack();
        }
        if (HJJTData.front().signalTime > kLineData->kLineData.front().dateTime) {
            //取历史
            getHJJTDataFront();
        }
        
        realCalculate(this->kLineData);
    }
    else {
        requestHJJTData();
    }
    
}

void HJJT::getHJJTDataFront()
{
//    vector<HJJTItem> gsList = getHJJTDataFromDB(HJJTData.front().signalTime, this->kLineData->getLimit());
//    
//    if(gsList.size()){
//        HJJTData.insert(HJJTData.begin(), gsList.begin(), gsList.end());
//    }
//    
//    if (HJJTData.front().signalTime > kLineData->kLineData.front().dateTime) {
        requestHJJTDataFront(ConvertToString(HJJTData.front().signalTime.getCurrentTime()));
//    }
    
}

void HJJT::getHJJTDataBack()
{
    requestHJJTDataBack(ConvertToString(HJJTData.back().signalTime.getCurrentTime()));
}

void HJJT::requestHJJTData()
{
    if (requesLock) {
        return;
    }
    int type = LineType::getRequestParamOfQuotationType(this->kLineData->quotationType);
    
    Config * config = Config::getInstance();
    
    map<string, string> data;
    data.insert(make_pair("Ver", "1"));
    data.insert(make_pair("IdxAlgoId", "7"));
    data.insert(make_pair("Market", ConvertToString(this->kLineData->marketType)));
    data.insert(make_pair("Instrument", ConvertToString(this->kLineData->nickName)));
    data.insert(make_pair("Period", std::to_string(type)));
//    data.insert(make_pair("quotationType", ConvertToString(type)));
    data.insert(make_pair("QueryTime", ConvertToString(kLineData->kLineData.back().dateTime.toSeconds() - hours(8))));
    
    NSLog(@"current:%s\nkLine:%s",YTXTime().date().toStringYYYYMMddHHmmss().c_str(), kLineData->kLineData.back().dateTime.GMT8().toStringYYYYMMddHHmmss().c_str());
    data.insert(make_pair("Limit", ConvertToString(this->kLineData->getDataLength())));
    data.insert(make_pair("Sort", "gt"));
    string routing = config->communicate.HJJTRouting;
    DataOption dataOption = DataOption(data, routing);
    requesLock = true;
    requestData("HJJTData"+this->kLineData->id, dataOption, "application/json");
}

void HJJT::requestHJJTDataBack(string date)
{
    if (requesLock) {
        return;
    }
    int type = LineType::getRequestParamOfQuotationType(this->kLineData->quotationType);
    
    Config * config = Config::getInstance();

    map<string, string> data;
    data.insert(make_pair("Ver", "1"));
    data.insert(make_pair("IdxAlgoId", "7"));
    data.insert(make_pair("Market", ConvertToString(this->kLineData->marketType)));
    data.insert(make_pair("Instrument", ConvertToString(this->kLineData->nickName)));
    data.insert(make_pair("Period", std::to_string(type)));
    //    data.insert(make_pair("quotationType", ConvertToString(type)));
    data.insert(make_pair("QueryTime", date));
    NSLog(@"%s",kLineData->kLineData.front().dateTime.toStringYYYYMMddHHmmss().c_str());

    data.insert(make_pair("Limit", ConvertToString(this->kLineData->getDataLength())));
    data.insert(make_pair("Sort", "lt"));
    string routing = config->communicate.HJJTRouting;
    DataOption dataOption = DataOption(data, routing);
    requesLock = true;
    requestData("HJJTDataBack"+this->kLineData->id, dataOption, "application/json");
}


void HJJT::requestHJJTDataFront(string date)
{
    //保证K线的数据领先
    if (requesLock) {
        return;
    }
    int type = LineType::getRequestParamOfQuotationType(this->kLineData->quotationType);
    
    Config * config = Config::getInstance();
    
    map<string, string> data;
    data.insert(make_pair("Ver", "1"));
    data.insert(make_pair("IdxAlgoId", "7"));
    data.insert(make_pair("Market", ConvertToString(this->kLineData->marketType)));
    data.insert(make_pair("Instrument", ConvertToString(this->kLineData->nickName)));
    data.insert(make_pair("Period", std::to_string(type)));
    //    data.insert(make_pair("quotationType", ConvertToString(type)));
    data.insert(make_pair("QueryTime", date));
    NSLog(@"%s",kLineData->kLineData.front().dateTime.toStringYYYYMMddHHmmss().c_str());

    data.insert(make_pair("Limit", ConvertToString(this->kLineData->getDataLength())));
    data.insert(make_pair("sort", "gt"));
    
    string routing = config->communicate.HJJTRouting;
    DataOption dataOption = DataOption(data, routing);
    requesLock = true;
    requestData("HJJTDataFront"+this->kLineData->id, dataOption, "application/json");
}

vector<HJJTItem> HJJT::parseHJJTData(YTXJson::Value data, YTXJson::Value info)
{
    vector<HJJTItem> ret;
    YTXJson::Value item;
    double beginPrice, endPrice, upLine, bottom, sUpLine, upMid, downMid, sBottom;
    int trend, temper;

    YTXTime tradedate, signalTime;
    HJJTPosition::HJJTPosition position;
    for (YTXJson::Value::iterator it = data.begin(); it != data.end(); ++it) {
        item = *it;
        beginPrice = item["BeginPrice"].asDouble();
        endPrice = item["EndPrice"].asDouble();
        upLine = item["UpLine"].asDouble();
        bottom = item["Bottom"].asDouble();
        sUpLine = item["SUpLine"].asDouble();
        upMid = item["UpMid"].asDouble();
        downMid = item["DownMid"].asDouble();
        sBottom = item["SBottom"].asDouble();
        trend = item["Trend"].asInt();
        temper = item["Temper"].asInt();
        signalTime = YTXTime(item["SignalTime"].asDouble()).GMT8();
        
        position = ( HJJTPosition::HJJTPosition)item["Position"].asInt();
        
        tradedate = YTXTime(item["TradingDay"].asDouble());
        
        HJJTItem gs = {
            signalTime,
            position,
            beginPrice,
            endPrice,
            upLine,
            bottom,
            sUpLine,
            upMid,
            downMid,
            sBottom,
            trend,
            temper,
            tradedate
        };
        
        ret.push_back(gs);
    }
    
    // info?
    return ret;
}

void HJJT::responseHJJTData(YTXJson::Value data, YTXJson::Value info)
{
    vector<HJJTItem> ret = parseHJJTData(data, info);
    initHJJTData(ret);
}

void HJJT::responseHJJTDataFront(YTXJson::Value data, YTXJson::Value info)
{
    vector<HJJTItem> ret = parseHJJTData(data, info);
    insertFrontHJJTData(ret);
}

void HJJT::responseHJJTDataBack(YTXJson::Value data, YTXJson::Value info)
{
    vector<HJJTItem> ret = parseHJJTData(data, info);
    pushHJJTData(ret);
}

void HJJT::initHJJTData(vector<HJJTItem> gsList)
{
    HJJTData = gsList;
//    saveHJJTDataToDB(HJJTData);
    this->kLineData->fire("request.stop", NULL);
}

void HJJT::pushHJJTData(vector<HJJTItem> gsList)
{
    if (gsList.size() == 0) {
        return;
    }
//    HJJTData.insert(HJJTData.end(), gsList.begin(), gsList.end());
//    saveHJJTDataToDB(gsList);
    HJJTData = getHJJTDataFromDB(YTXTime(2200,1,1,0,0,0), kLineData->getDataLengthWithoutClose()+1);
    this->kLineData->fire("load", NULL);
}


void HJJT::insertFrontHJJTData(vector<HJJTItem> gsList)
{
    if (gsList.size() == 0) {
        return;
    }
//    HJJTData.insert(HJJTData.begin(), gsList.begin(), gsList.end());
//    saveHJJTDataToDB(gsList);
    HJJTData = getHJJTDataFromDB(YTXTime(2200,1,1,0,0,0), kLineData->getDataLengthWithoutClose()+1);
    this->kLineData->fire("load", NULL);
}

//bool HJJT::isInLatestNewK(YTXTime tradedate1, YTXTime tradedate2){
//    if (LineType::isMinuteLine(quotationType)){
//        return (tradedate1 + minutes( LineType::getRequestParamOfQuotationType(quotationType) ) ) >= tradedate2;
//    }
//    else if (quotationType == LineType::L1d) {
//        return (tradedate1 + days(1) ) >= tradedate2;
//    }
//    else if (quotationType == LineType::L1w) {
//        YTXTimeDuration dateDiff = tradedate2.date() - tradedate1.date();
//        return  LineType::getRequestParamOfQuotationType(quotationType) >= dateDiff.getDiffDay();
//    }
//    else if(quotationType == LineType::L1M){
//        YTXTimeDate newMonth = (tradedate1.date().end_of_month() + days(1)).end_of_month() + days(1);
//        return  newMonth >= tradedate2.date();
//    }
//    return false;
//}


bool HJJT::saveHJJTDataToDB(vector<HJJTItem> ret)
{
    HJJTSQLite HJJTSQLite;
    HJJTSQLite.createKLineDataTableIfNotExit(HJJTSQLite::getTableName(kLineData));
    return HJJTSQLite.insertData(HJJTSQLite::getTableName(kLineData), ret);
}

vector<HJJTItem> HJJT::getHJJTDataFromDB(YTXTime time, const unsigned int limit)
{
    vector<HJJTItem> ret;
    HJJTSQLite HJJTSQLite;
    
    HJJTSQLite.getDataFromDB(HJJTSQLite.getTableName(kLineData), time ,&ret, limit);
    
    return ret;
}

void HJJT::clearIfParentDataChanged(const Quotation * data)
{
    if (!isSameParentData(data)) {
        cleanData();
        requesLock = false;
    }
}

void HJJT::cleanData()
{
    HJJTData.clear();
    indexData.clear();
    lineData.clear();
}

int HJJT::getDataLength() const
{
    return (int)HJJTData.size();
}
